package org.monster.context.core;

import org.dom4j.DocumentException;
import org.monster.context.core.parameter.HttpResponse;
import org.monster.context.core.request.HttpRequest;
import org.monster.context.reader.tag.ServletTag;
import org.monster.context.servlet.ServletContainer;
import org.monster.context.servlet.ServletContextConfig;
import org.monster.context.servlet.ServletExecutor;
import org.monster.context.util.URIUtils;

import javax.servlet.http.HttpServlet;
import java.util.List;

/**
 * 应用上下文
 *
 * @author Monster
 */
public class ApplicationContext {

    /**
     * 服务者容器
     */
    private final ServletContainer container = ServletContainer.getContainer();
    /**
     * 服务者配置缓存
     */
    private final ServletConfigCache servletConfigCache = ServletConfigCache.getServletConfigCache();
    /**
     * 服务者执行器
     */
    private final ServletExecutor executor;
    /**
     * 服务者上下文配置
     */
    private final ServletContextConfig config;
    /**
     * 应用类加载器实现
     */
    private final ApplicationClassLoaderImpl classLoader;

    /**
     * 构造方法
     *
     * @param executor    服务者执行器
     * @param config      服务者上下文配置
     * @param classLoader 应用类加载器实现
     */
    public ApplicationContext(ServletExecutor executor,
                              ServletContextConfig config, ApplicationClassLoaderImpl classLoader) {
        this.executor = executor;
        this.config = config;
        this.classLoader = classLoader;
    }

    /**
     * 服务
     *
     * @param request  请求
     * @param response 响应
     * @throws ClassNotFoundException 类未找到异常
     * @throws DocumentException      文档异常
     */
    public void service(HttpRequest request, HttpResponse response)
            throws ClassNotFoundException, DocumentException {
        // 请求的URI
        String requestURI = request.getRequestURI();
        String appName = URIUtils.startWithURI(requestURI);
        // 获取请求的项目的classes目录下的加载（在classes下还有package包文件夹）
        classLoader.getWebClassLoader(appName);
        String endsURI = URIUtils.allEndsWithURI(requestURI);
        HttpServlet servlet = matchTag(appName, endsURI);
        String classpath = null;
        if (servlet == null) {
            classpath = config.getServletConfig(request);
            servlet = container.getServlet(appName + "_" + classpath);
        }
        if (servlet == null) {
            if (classpath != null) {
                Class<?> clazz = classLoader.loadClass(classpath);
                servlet = executor.service(request, response, clazz);
                container.addServlet(appName + "_" + classpath, servlet);
            }
        } else {
            executor.service(request, response, servlet);
        }
    }

    /**
     * 匹配 标签
     *
     * @param appName 应用名
     * @param endsURI 结束uri
     * @return http服务者
     */
    private HttpServlet matchTag(String appName, String endsURI) {
        List<ServletTag> tags = servletConfigCache.getTags(appName);
        if (tags == null) {
            return null;
        }
        for (ServletTag servletTag : tags) {
            if (servletTag.getMappingUrlPattern().equals(endsURI)) {
                String classess = servletTag.getServletClass();
                return container.getServlet(appName + "_" + classess);
            }
        }
        return null;
    }

}
